package com.zero.execute.reader;

import com.zero.common.Common;
import com.zero.core.ZeroContext;
import com.zero.util.FreemarkerUtils;
import com.zero.xmodel.JdbcConfigPO;
import com.zero.xmodel.PackagePO;
import freemarker.template.Template;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * xml文件读执行器
 *
 * @author wuxi
 * @date 2020-07-27
 */
public class XMLReader {

    private ZeroContext zeroContext;

    public XMLReader() {
        this.zeroContext = new ZeroContext();
    }

    public ZeroContext read() {
        //获取操作系统，获取当前系统文件夹生成间隔符
        readOs();
        //读取xml
        Document document = getDocument();
        //读取项目路径
        readProjectPath(document);
        //解析mysql
        readerMysql(document);
        //创建3层目录
        readerPage(document);
        //读取表名
        readTableInfo(document);
        //初始化模板引擎的模板
        initFreemarkerTemplate();
        return this.zeroContext;
    }

    /**
     * 获取节点
     *
     * @return Document
     */
    private Document getDocument() {
        InputStream stream = this.getClass().getResourceAsStream(this.zeroContext.getSeparator() + "main.xml");
        DocumentBuilderFactory factory = DocumentBuilderFactory
                .newInstance();
        Document doc = null;
        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            doc = builder.parse(stream);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return doc;
    }

    /**
     * 读取项目路径
     *
     * @param document xml:doc
     */
    private void readProjectPath(Document document) {
        String projectPath = getNodeValue(document, "project-path");
        if (StringUtils.isBlank(projectPath)) {
            this.zeroContext.setProjectPath(Common.path + this.zeroContext.getSeparator() + "dist");
        } else {
            this.zeroContext.setProjectPath(projectPath);
        }
    }

    /**
     * 获取当前系统的文件的分割符
     */
    private void readOs() {
        String system = System.getProperty("os.name");
        if (system.toLowerCase().startsWith("win")) {
            this.zeroContext.setSeparator("\\");
        } else {
            this.zeroContext.setSeparator("/");
        }
    }

    /**
     * xml解析：获取全部需要解析的表信息
     *
     * @param document doc
     */
    private void readTableInfo(Document document) {
        String pre = getNodeValue(document, "pre");
        this.zeroContext.setPreTable(pre);
        List<String> tableNames = new ArrayList<>();
        NodeList tables = document.getElementsByTagName("tables");
        if (tables.getLength() > 0) {
            NodeList childNodes = tables.item(0).getChildNodes();
            for (int i = 0; i < childNodes.getLength(); i++) {
                if ("name".equals(childNodes.item(i).getNodeName())) {
                    String nodeValue = childNodes.item(i).getFirstChild().getNodeValue();
                    tableNames.add(nodeValue);
                }
            }
        }
        if (tableNames.size() > 0) {
            this.zeroContext.setTableNames(tableNames);
        }
    }

    /**
     * xml解析: jdbc属性
     *
     * @param document doc
     */
    private void readerMysql(Document document) {
        JdbcConfigPO po = new JdbcConfigPO();
        po.setDriverName(getNodeValue(document, "driver-class-name"));
        po.setHost(getNodeValue(document, "host"));
        po.setDbName(getNodeValue(document, "dbName"));
        po.setUserName(getNodeValue(document, "userName"));
        po.setPassword(getNodeValue(document, "password"));
        this.zeroContext.setJdbcConfigPO(po);
    }

    /**
     * xml解析：设置全部包名
     *
     * @param document doc
     */
    private void readerPage(Document document) {
        String dist = getNodeValue(document, "file-path");
        dist = StringUtils.isNotBlank(dist) ? dist : "dist";
        this.zeroContext.setFilePath(dist);
        PackagePO po = new PackagePO();
        po.setEntityPackageName(getNodeValueByDef(document, "entity-package-name", this.zeroContext.getSeparator() +
                "entity"));
        po.setServicePackageName(getNodeValueByDef(document, "service-package-name", this.zeroContext.getSeparator() + "service"));
        po.setDaoPackageName(getNodeValueByDef(document, "dao-package-name", this.zeroContext.getSeparator() + "dao"));
        this.zeroContext.setPackagePO(po);
    }

    /**
     * 解析xml：获取节点信息
     *
     * @param document doc
     * @param key      key
     * @param def      默认值
     * @return 解析xml：获取节点信息
     */
    private String getNodeValueByDef(Document document, String key, String def) {
        String value = getNodeValue(document, key);
        return StringUtils.isNotBlank(value) ?
                this.zeroContext.getProjectPath() + this.zeroContext.getFilePath() + value
                : this.zeroContext.getProjectPath() + this.zeroContext.getFilePath() + def;
    }

    /**
     * 解析xml：获取节点信息
     *
     * @param document doc
     * @param key      key
     * @return 解析xml：获取节点信息
     */
    private String getNodeValue(Document document, String key) {
        NodeList elementsByTagName = document.getElementsByTagName(key);
        if (elementsByTagName.getLength() == 0) {
            return null;
        }
        Node node = document.getElementsByTagName(key).item(0);
        return node.getFirstChild().getNodeValue();
    }

    /**
     * 一次将全部模板初始化，减少读取模板次数
     */
    private void initFreemarkerTemplate() {
        Map<String, Template> template = new HashMap<>(4);
        Template daoTemplate = FreemarkerUtils.getTemplate("dao.ftl");
        Template entityTemplate = FreemarkerUtils.getTemplate("entity.ftl");
        Template serviceTemplate = FreemarkerUtils.getTemplate("service.ftl");
        Template serviceImplTemplate = FreemarkerUtils.getTemplate("serviceImpl.ftl");
        template.put("daoTemplate", daoTemplate);
        template.put("entityTemplate", entityTemplate);
        template.put("serviceTemplate", serviceTemplate);
        template.put("serviceImplTemplate", serviceImplTemplate);
        this.zeroContext.setFreemarkerTemplateMap(template);
    }


}